package org.swust.sysmonitorapp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.swust.sysmonitorapp.dto.HealthDataDto;
import org.swust.sysmonitorapp.entity.HealthData;
import org.swust.sysmonitorapp.entity.QHealthData;
import org.swust.sysmonitorapp.entity.SysUser;
import org.swust.sysmonitorapp.mapper.HealthDataMapper;
import org.swust.sysmonitorapp.service.IHealthDataService;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 健康数据服务实现类
 *
 * @since 2024-03-21
 */
@Service
public class HealthDataServiceImpl extends ServiceImpl<HealthDataMapper, HealthData> implements IHealthDataService {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public IPage<HealthDataDto> pageHealthData(Page page, QHealthData query) {
        return baseMapper.pageHealthData(page, query);
    }

    @Override
    public HealthDataDto getLatestData(String deviceId) {
        return baseMapper.getLatestData(deviceId);
    }

    @Override
    public Map<String, Object> getUserHeartRateStats(Long userId, String startTime, String endTime) {
        LocalDateTime start = startTime != null ? LocalDateTime.parse(startTime, formatter) : null;
        LocalDateTime end = endTime != null ? LocalDateTime.parse(endTime, formatter) : null;

        LambdaQueryWrapper<HealthData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HealthData::getUserId, userId);
        if (start != null) {
            queryWrapper.ge(HealthData::getMeasureTime, start);
        }
        if (end != null) {
            queryWrapper.le(HealthData::getMeasureTime, end);
        }
        queryWrapper.orderByAsc(HealthData::getMeasureTime);

        List<HealthData> dataList = list(queryWrapper);

        Map<String, Object> result = new HashMap<>();
        if (dataList.isEmpty()) {
            result.put("dataPoints", List.of());
            result.put("max", 0);
            result.put("min", 0);
            result.put("avg", 0);
            return result;
        }

        List<Map<String, Object>> dataPoints = dataList.stream()
                .map(data -> {
                    Map<String, Object> point = new HashMap<>();
                    point.put("time", data.getMeasureTime().format(formatter));
                    point.put("value", data.getHeartRate());
                    return point;
                })
                .collect(Collectors.toList());

        int max = dataList.stream()
                .mapToInt(HealthData::getHeartRate)
                .max()
                .orElse(0);

        int min = dataList.stream()
                .mapToInt(HealthData::getHeartRate)
                .min()
                .orElse(0);

        double avg = dataList.stream()
                .mapToInt(HealthData::getHeartRate)
                .average()
                .orElse(0.0);

        result.put("dataPoints", dataPoints);
        result.put("max", max);
        result.put("min", min);
        result.put("avg", Math.round(avg * 10) / 10.0);

        return result;
    }

    @Override
    public Map<String, Object> getUserBloodOxygenStats(Long userId, String startTime, String endTime) {
        LocalDateTime start = startTime != null ? LocalDateTime.parse(startTime, formatter) : null;
        LocalDateTime end = endTime != null ? LocalDateTime.parse(endTime, formatter) : null;

        LambdaQueryWrapper<HealthData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HealthData::getUserId, userId);
        if (start != null) {
            queryWrapper.ge(HealthData::getMeasureTime, start);
        }
        if (end != null) {
            queryWrapper.le(HealthData::getMeasureTime, end);
        }
        queryWrapper.orderByAsc(HealthData::getMeasureTime);

        List<HealthData> dataList = list(queryWrapper);

        Map<String, Object> result = new HashMap<>();
        if (dataList.isEmpty()) {
            result.put("dataPoints", List.of());
            result.put("max", 0);
            result.put("min", 0);
            result.put("avg", 0);
            return result;
        }

        List<Map<String, Object>> dataPoints = dataList.stream()
                .map(data -> {
                    Map<String, Object> point = new HashMap<>();
                    point.put("time", data.getMeasureTime().format(formatter));
                    point.put("value", data.getBloodOxygen());
                    return point;
                })
                .collect(Collectors.toList());

        BigDecimal max = dataList.stream()
                .map(HealthData::getBloodOxygen)
                .max(Comparator.naturalOrder())
                .orElse(BigDecimal.ZERO);

        BigDecimal min = dataList.stream()
                .map(HealthData::getBloodOxygen)
                .min(Comparator.naturalOrder())
                .orElse(BigDecimal.ZERO);

        BigDecimal sum = dataList.stream()
                .map(HealthData::getBloodOxygen)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal avg = dataList.isEmpty() ? BigDecimal.ZERO :
                sum.divide(new BigDecimal(dataList.size()), 1, RoundingMode.HALF_UP);

        result.put("dataPoints", dataPoints);
        result.put("max", max);
        result.put("min", min);
        result.put("avg", avg);

        return result;
    }

    @Override
    public boolean save(HealthData entity) {
        return super.save(entity);
    }
} 